package xworker.swt.dataObject.datastore;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.*;
import org.xmeta.ActionContext;
import org.xmeta.Bindings;
import org.xmeta.Thing;
import org.xmeta.World;
import org.xmeta.util.UtilData;
import org.xmeta.util.UtilMap;
import org.xmeta.util.UtilString;
import xworker.swt.app.view.swt.data.events.SwtStoreUtils;
import xworker.dataObject.DataObject;
import xworker.dataObject.DataObjectList;
import xworker.dataObject.DataStore;
import xworker.dataObject.PageInfo;
import xworker.lang.executor.Executor;
import xworker.swt.custom.ItemRowEditor;
import xworker.swt.custom.TableCellEditor;
import xworker.swt.form.ThingDescriptorForm;
import xworker.swt.util.SwtUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TableDataStoreListener extends ControlDataStoreListener{
    private static final String TAG = TableDataStoreListener.class.getName();

    final Table table;
    final List<TableDataStoreColumn> columns = new ArrayList<>();
    boolean editable;
    String editMethod;
    Control tableCursor;
    Thing cursorThing;

    public TableDataStoreListener(Table table, DataStore dataStore, ActionContext actionContext){
        super(table, dataStore, actionContext);

        this.table = table;
        this.table.setData("_store", dataStore);
        table.addListener(SWT.Selection, event ->{

        });
        table.addListener(SWT.DefaultSelection, event ->{
            //按行编辑
            if(editable && "row".equals(editMethod)) {
                //表格中的行
                TableItem item = (TableItem) event.item;

                //创建编辑窗体
                ActionContext ac = new ActionContext();
                Thing store = (Thing) table.getData("_store");
                ac.put("store", store);
                ac.put("parent", table.getShell());
                Thing editorThing = World.getInstance().getThing("xworker.swt.app.view.swt.widgets.table.DataObjectGridRowEditor/@shell");
                editorThing.doAction("create", ac);
                ((Thing) ac.get("form")).doAction("setDataObject", ac, UtilMap.toMap("dataObject", item.getData()));
                Shell shell = (Shell) ac.get("shell");
                shell.pack();
                SwtUtils.centerShell(shell);
                shell.open();
            }
        });

        onReconfig(dataStore, dataStore.getDataObject());
        if(dataStore.isLoaded()){
            onLoaded(dataStore);
        }
    }

    @Override
    public void onReconfig(DataStore dataStore, Thing dataObject) {
        exec(()->{
            //删除所有数据
            table.removeAll();
            columns.clear();

            //删除所有列
            for(TableColumn column : table.getColumns()){
                column.dispose();
            }

            //创建列
            for(Thing attr : dataObject.getChilds("attribute")){
                if(attr.getBoolean("viewField") && attr.getBoolean("showInTable") && attr.getBoolean("gridEditor")){
                    TableDataStoreColumn column = new TableDataStoreColumn(this, dataStore, attr);
                    columns.add(column);
                }
            }

            if(tableCursor != null){
                tableCursor.dispose();
            }

            //表格是否可编辑
            editable = dataStore.isEditable();
            if(editable){
                editMethod = dataStore.getEditMethod();  //编辑方式

                if(!"row".equals(editMethod)){
                    //按单元格编辑
                    cursorThing = new Thing("xworker.swt.widgets.Table/@TableCursorEditor");
                    List<Thing> columns = new ArrayList<>();
                    for(TableDataStoreColumn column : this.columns){
                        columns.add(column.getAttribute());
                    }

                    table.setData("_columns", columns);
                    cursorThing.initDefaultValue();
                    //cursorThing.put("name", store.getString("name") + "CursorEditor");
                    cursorThing.put("dataType", "store");


                    int index = 0;
                    for(Thing column : columns){
                        if(column.getBoolean("editable")){
                            //根据输入类型创建相应的编辑器
                            //String inputType = column.getStringBlankAsNull("inputtype");
                            Thing columnEditor = new Thing("xworker.swt.custom.TableCursorEditor/@ColumnEditor");
                            columnEditor.put("column", "" + index);
                            cursorThing.addChild(columnEditor);

                            Thing attrEditor = new Thing("xworker.swt.custom.tableEditors.AttributeEditor");

                            Thing attribute = createColumnWithDataStore(column);
                            attrEditor.addChild(attribute, false);
                            columnEditor.addChild(attrEditor);
                        }
                        index++;
                    }

                    try{
                        Bindings bindings = actionContext.push(null);
                        bindings.put("parent", table);

                        tableCursor = cursorThing.doAction("create", actionContext);
                        //Clipboard.add(cursorThing);
                    }finally{
                        actionContext.pop();
                    }
                }
            }

        });
    }

    public static Thing createColumnWithDataStore(Thing attribute){
        //在表格编辑时重新生成column的符合编辑的属性定义，尤其是生成数据仓库。
        //String type = "edit";
        Thing oldAttribute = attribute;
        Thing column = attribute;
        Thing at = (Thing) column.get("EditConfig@0");

        String attributePath = attribute.getMetadata().getPath(); //保存原有的事物路径，方便Desinger能够正确打开原先的属性
        //log.info("attributePath=" + attributePath);
        if(at != null){
            //由于config中只定义了样式，没有属性的基本数据等，所以复制
            Thing attemp = at.detach();
            Map<String, Object> temp = new HashMap<>();
            temp.putAll(attribute.getAttributes());
            temp.putAll(attemp.getAttributes());
            attemp.getAttributes().putAll(temp);
            attemp.put("name", attribute.getString("name"));
            attemp.put("label", attribute.getString("label"));
            attemp.put("pattern", attribute.getString("editPattern"));
            attemp.put("descriptors", attribute.getString("descriptors"));
            attribute = attemp;
        }else{
            attribute = attribute.detach();
            attribute.put("pattern", attribute.getString("editPattern"));
        }
        attribute.setData("_originalityAttributePath", attributePath);

        String inputtype = attribute.getStringBlankAsNull("inputtype");
        if (UtilData.equalsOne(inputtype, new String[] { "select", "inputSelect", "multSelect" })) {
            Thing dataStoreThing = ThingDescriptorForm.getDataStoreThing(oldAttribute);
            if(dataStoreThing != null) {
                attribute.setData("dataStore", dataStoreThing);
                attribute.put("inputattrs", dataStoreThing.getMetadata().getPath());
            }else{
                String dobj = attribute.getString("relationDataObject");
                String inputattrs = attribute.getStringBlankAsNull("inputattrs");
                if (dobj != null && !"".equals(dobj) && inputattrs == null) {
                    // 如果属性是多对一关联其他属性的，并且是下拉选择框，那么初始化相关下拉框的功能
                    Thing dataStore = new Thing("xworker.swt.Commons/@DataStore");
                    dataStore.initDefaultValue();
                    dataStore.put("paging", "no"); // 下拉列表不分页
                    String store = attribute.getStringBlankAsNull("store");
                    if (store != null) {
                        // 字段定义了引擎其他数据仓库
                        dataStore.put("storeRef", attribute.getString("store"));
                        dataStore.put("attachToParent", "true");
                        dataStore.put("loadBackground", "true");
                    } else {
                        // 创建数据仓库
                        dataStore.put("dataObject", attribute.getString("relationDataObject"));
                        dataStore.put("queryConfig", attribute.getString("relationQueryConfig"));
                        if (dataStore.getStringBlankAsNull("queryConfig") == null) {
                            Thing qcfg = (Thing) column.get("SelectCondition@0");
                            if (qcfg != null) {
                                dataStore.put("queryConfig", qcfg.getMetadata().getPath());
                            }
                        }
                        dataStore.put("autoLoad", "true");
                        dataStore.put("attachToParent", "true");
                        dataStore.put("loadBackground", "true");
                        dataStore.put("labelField", attribute.getString("relationLabelField"));
                    }
                    attribute.setData("dataStore", dataStore);
                    attribute.put("inputattrs", dataStore.getMetadata().getPath());
                }
            }
        }

        return attribute;
    }

    @Override
    public void onLoaded(DataStore dataStore) {
        exec(()-> {
            try {
                if (table.isDisposed()) {
                    return;
                }

                //先清空数据
                table.removeAll();
                DataObjectList records = dataStore.getDatas();
                if (records != null) {
                    //log.info("records=" + store.records);
                    for (DataObject record : records) {
                        createItem(table, record, -1, actionContext);
                    }

                    PageInfo pageInfo = dataStore.getPageInfo();
                    if (pageInfo != null) {
                        for (TableColumn column : table.getColumns()) {
                            if (pageInfo.getSort() != null && pageInfo.getSort().equals(column.getData("name"))) {
                                table.setSortColumn(column);
                                if ("DESC".equals(pageInfo.getDir())) {
                                    table.setSortDirection(SWT.DOWN);
                                } else {
                                    table.setSortDirection(SWT.UP);
                                }
                                break;
                            }
                        }
                    }
                }

                selectionChanged();
            } catch (Throwable t) {
                Executor.error(TAG, "TableDataStoreListener onLoaded error", t);
            }
        });
    }

    @Override
    public void onTotalCountUpdated(DataStore dataStore) {

    }

    @Override
    public void onChanged(DataStore dataStore) {
        exec(() -> {
            int index = 0;
            List<DataObject> datas = dataStore.getDatas();
            for(DataObject data : datas){
                if(table.getItemCount() <= index){
                    break;
                }

                TableItem item = table.getItem(index);
                if(item.getData() != data){
                    item.dispose();
                    createItem(table, data, index, actionContext);
                }
                index++;
            }
            if(index < datas.size()){
                for(int i=index; i<datas.size(); i++){
                    createItem(table, datas.get(i), -1, actionContext);
                }
            }else  if(index < table.getItemCount()){
                table.remove(index, table.getItemCount() - 1);
            }

            selectionChanged();
        });
    }

    @Override
    public void beforeLoad(DataStore dataStore, Thing condition, Map<String, Object> params) {
        exec(()->{
            table.removeAll();

            TableItem item = new TableItem(table, SWT.NONE);
            item.setText(UtilString.getString("lang:d=加载中...&en=Loading...", actionContext));
        });
    }

    @Override
    protected void selectionChanged() {
        exec(() -> {
            List<DataObject> datas = new ArrayList<>(getSelectedItems());
            for(TableItem item : table.getItems()){
                if(datas.size() == 0){
                    break;
                }

                boolean ok = false;
                for(DataObject data : datas) {
                    if (item.getData() == data){
                        table.setSelection(item);
                        item.setChecked(true);
                        ok = true;
                        datas.remove(data);
                        break;
                    }
                }

                if(!ok){
                    item.setChecked(false);
                }
            }
        });
    }

    private List<Thing> getColumnThings(){
        List<Thing> columns = new ArrayList<>();
        for(TableDataStoreColumn column : this.columns){
            columns.add(column.getAttribute());
        }

        return columns;
    }

    private void createItem(Table table, DataObject record, Integer index, ActionContext actionContext) {
        //过滤重复的数据
        for(TableItem item : table.getItems()) {
            if(item.getData() == record) {
                return;
            }
        }

        //log.info("record=" + record);
        String[] texts = recordToRowTexts(record);
        //log.info("texts=" + texts);
        TableItem tableItem;
        if(index != null && index >= 0 && index <= table.getItemCount()) {
            tableItem = new TableItem(table, SWT.NONE, index);
        }else {
            tableItem = new TableItem(table, SWT.NONE);
        }
        tableItem.setText(texts);
        tableItem.setData(record);
        tableItem.setData("dataStore", dataStore);

        updateItemICF(tableItem, record, actionContext);

        tableItem.setData("_store_record", record);
        if((table.getStyle() & SWT.CHECK) == SWT.CHECK){
            if(record.getBoolean(DataObject.CHECKED_ATTRIBUTE_NAME)){
                tableItem.setChecked(true);
            }
        }

        //显示编辑器，如果表格可编辑，且字段gridShowEditor=true
        //当表格可以编辑时同时也会有cursorThing，参看creatRowEditor(ActionContext)
        if(cursorThing != null) {
            List<Thing> columns = getColumnThings();
            ItemRowEditor rowEditor = new ItemRowEditor(tableItem);
            for(int i=0; i<columns.size(); i++) {
                Thing column = columns.get(i);
                if(!column.getBoolean("gridShowEditor")) {
                    continue;
                }

                TableCellEditor cellEditor = new TableCellEditor(tableItem, i, cursorThing,  actionContext);
                rowEditor.addItemEditor(cellEditor);
            }
            tableItem.setData("__TableDataStore_ItemRowEditor__", rowEditor);
        }
        //showTableEditor(self, table, tableItem, record, actionContext);

        //监听数据对象的变化，自动更新表格
        new TableDataStoreDataObjectListener(this, record, tableItem);
    }

    private void updateItemICF(TableItem item, DataObject record, ActionContext actionContext) {
        String icon = (String) record.doAction("getIcon", actionContext, "tableItem", item);
        if(icon != null && !"".equals(icon)) {
            Image image = SwtUtils.createImage(item.getParent(), icon, actionContext);
            if(image != null) {
                item.setImage(image);
            }
        }

        String color = (String) record.doAction("getColor", actionContext, "tableItem", item);
        if(color != null && !"".equals(color)) {
            Color c = SwtUtils.createColor(item.getParent(), color, actionContext);
            if(c != null) {
                item.setBackground(c);
            }
        }

        String value = (String) record.doAction("getFont", actionContext, "tableItem", item);
        if(value != null && !"".equals(value)) {
            Font font = SwtUtils.createFont(item.getParent(), value, actionContext);
            if(font != null) {
                item.setFont(font);
            }
        }

        //执行updateSWTTableItem
        record.doAction("updateSWTTableItem", actionContext, "tableItem", item);

    }

    private String[] recordToRowTexts(DataObject record){
        List<String> texts = new ArrayList<>();
        for(TableDataStoreColumn dc :  columns){
            Thing column = dc.getAttribute();
            record.getLabel(column.getMetadata().getName());
            String text = SwtStoreUtils.getColumnDisplayText(record, column, actionContext);

            texts.add(text);
        }

        String[] ts = new String[texts.size()];
        for(int i=0; i<texts.size(); i++){
            ts[i] = texts.get(i);
        }
        return ts;
    }

    protected void updateItem( TableItem item, DataObject record, ActionContext actionContext) {
        //log.info("DataStore: update table item");
        String[] texts = recordToRowTexts(record);

        item.setText(texts);

        updateItemICF(item, record, actionContext);

        if((item.getParent().getStyle() & SWT.CHECK) == SWT.CHECK){
            item.setChecked(record.getBoolean(DataObject.CHECKED_ATTRIBUTE_NAME));
        }

        ItemRowEditor rowEditor = (ItemRowEditor) item.getData("__TableDataStore_ItemRowEditor__");
        if(rowEditor != null) {
            rowEditor.update();
        }
    }
}
